import { director, game, Node } from "cc";
import { asapScheduler, asyncScheduler, interval, timer, startWith, map } from "../../rxjs";
import { Observable } from "../internal/Observable";
import { nodeScheduler, sceneScheduler } from "./schedule/creator";
import { tween } from "cc";

// 时间段单位为毫秒

// 本帧，尽快发出 （跟creator无关）
export function Asap(): Observable<number> {
    return timer(0, asapScheduler)
}

// 本帧，异步发出（跟creator无关）
export function Async(): Observable<number> {
    return timer(0, asyncScheduler);
}

// 下一帧发出
export function NextFrame(): Observable<number> {
    return timer(0, sceneScheduler);
}

export function EveryFrame() {
    return IntervalStartNow(0).pipe(map(_ => game.deltaTime));
}

export function EveryFrameScene(duration?: number, node?: Node): Observable<number> {
    return new Observable(observer => {
        let t = tween(node ?? director.getScene()).to(duration ?? Infinity, {}, {
            onUpdate: (target, ratio) => {
                // console.log('onUpdate', ratio);
                observer.next(ratio);
            },
            onComplete: (target) => {
                // console.log('onComplete');
                observer.next(1);
                observer.complete();
            }
        }).start();
        return () => {
            t.destroySelf();
            t = null;
        }
    });
}

// due毫秒后发出或到达指定时间后发出
export function Timer(due: number | Date, obj?: Node): Observable<number> {
    if (typeof due == 'number') due *= 1000;
    if (obj == null) {
        return timer(due, sceneScheduler);
    }
    return timer(due, nodeScheduler(obj));
}

// period周期循环调用
export function Interval(period, obj?: Node): Observable<number> {
    const scheduler = obj == null ? sceneScheduler : nodeScheduler(obj);
    return interval(period * 1000, scheduler);
}

// 与Interval相同，不过是第一次立即开始
export function IntervalStartNow(period, obj?: Node): Observable<number> {
    return Interval(period, obj).pipe(startWith(-1), map(_ => _ + 1));
}

// Interval函数的缓动版本
// 输入时间和输出次数，返回一个在时间上不均匀的（按照缓动函数）输出序列
// list按顺序输入id，最终停转到chooseId上面
// 例如参数times为20时，会有序收到0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19
export function IntervalWithTween(totalTime: number, times: number, tweenFunc: (number) => number) {
    return new Observable<number>(observer => {
        let c = 0;
        let step = 1 / times;
        let startTime = game.totalTime;
        // 每帧调用
        let sub = EveryFrame().subscribe(_ => {
            let curTime = game.totalTime - startTime;
            let t = curTime / (totalTime * 1000);
            //@ts-ignore
            let value = tweenFunc(t);
            // console.log('curTime', curTime, 'totalTime', totalTime, 't', t, 'value', value, 'step', step, 'c', c, 'blingTimes', times);
            if (value >= step * (c + 1) || t >= 1) { // 如果仅用前面一个条件，那么当t为1.001时，value为0.99903...，不会触发,这是不合理的
                observer.next(c);
                c++;
            }
            if (c >= times) {
                observer.complete();
            }
        });
        return () => {
            sub.unsubscribe();
        }
    });
}
